import {
  CSLine,
  CSMesh,
  EventObject,
  EventsRes,
  RENDERORDER,
} from '@amcax/base';
import { ctx2, userEvents } from '@app-cad/module';
import {
  Object3D,
  OrthographicCamera,
  PerspectiveCamera,
  Vector2,
} from 'three-legacy';
import { DimInfo, DimObject } from './type';
import { SelectionBox } from 'three-legacy/examples/jsm/interactive/SelectionBox';
import { MarqueeSelector } from './marqueeSelector';
import { dimRender } from './render';
import { DimLinear } from '../dimension/DimLinear';
import { isFunction } from 'lodash';
import { DimRadiusTool } from '../dimension/DimRadiusTool';
import { DimDiameterTool } from '../dimension/DimDiameter';
import { DimAngleTool } from '../dimension/DimAngleTool';
import { DIM_EVENTS } from '@app-base/common/Constants';

export default class DimPicker {
  private readonly mouse = new Vector2();
  private container: HTMLElement;
  private dimensionGroup: Object3D;
  static instance: DimPicker;
  private camera: PerspectiveCamera | OrthographicCamera;
  private pointerDownPos: {
    clientPos: { clientX: number; clientY: number };
    mouse: { x: number; y: number };
  };
  private hoveredObject; // 当前悬停的对象
  private selectedObjects: DimObject[] = []; // 当前选中的对象
  private selectionBox; // 框选器
  private marqueeSelector; // 框选框
  static getInstance(): DimPicker {
    if (!this.instance) {
      this.instance = new DimPicker();
    }
    return this.instance;
  }
  constructor() {
    this.init();
  }
  getSelectedObj() {
    return this.selectedObjects
      .map((obj) => getObjectInfo<DimInfo>(obj))
      .filter((value) => value !== undefined);
  }
  init(): void {
    this.container = ctx2.viewer.sceneSetup.container;
    this.dimensionGroup = dimRender().dimensionGroup;
    this.camera = ctx2.viewer.sceneSetup.camera;

    userEvents.on(DIM_EVENTS.DIM_CSS_2D_INPUT_FOCUS, this.clickNull.bind(this));
  }
  pick(e: EventObject) {
    this.mouse.x = (e.mouse.x / this.container.clientWidth) * 2 - 1;
    this.mouse.y = -(e.mouse.y / this.container.clientHeight) * 2 + 1;

    const raycaster = ctx2.viewer.sceneSetup.createRaycaster(
      e.mouse.x,
      e.mouse.y,
      0,
      10, // 草图的线可能距离比较近，所以设置一个较小的threshold
    );
    const intersects = raycaster.intersectObjects(
      this.dimensionGroup.children,
      true,
    );
    setTimeout(() => ctx2.viewer.requestRender());
    if (intersects.length > 0) {
      if (this.selectedObjects?.length <= 0) {
        this.unHover();
      }
      const line = intersects.find(({ object }) => {
        return object instanceof CSLine || object instanceof CSMesh;
      })?.object as CSLine | CSMesh;
      const hoveredObject =
        line instanceof CSLine
          ? line?.parent
          : line instanceof CSMesh
            ? line?.parent?.parent
            : null;
      this.hoveredObject = hoveredObject;
      // 如果当前悬停的对象不在已选中列表中，则高亮
      if (this.selectedObjects.indexOf(this.hoveredObject) < 0) {
        if (this.hoveredObject) {
          this.hoveredObject.renderOrder = RENDERORDER.EDGE_H;
        }
        const fun = this.hoveredObject?.highlight;
        if (isFunction(fun)) {
          fun.call(this.hoveredObject);
        }
      }
      return this.hoveredObject;
    } else {
      // 如果当前悬停的对象不在已选中列表中，则取消高亮
      if (this.selectedObjects.indexOf(this.hoveredObject) < 0) {
        this.hoveredObject?.setNormalColor();
      }
      this.hoveredObject = null;
      return null;
    }
  }
  clickNull() {
    this.hoveredObject?.setNormalColor();
    this.hoveredObject = null;
    this.selectedObjects.forEach((obj) => {
      obj.setNormalColor();
    });
    this.selectedObjects = [];
  }
  unHover() {
    this.hoveredObject?.setNormalColor();
    this.hoveredObject = null;
  }
  select(event?: PointerEvent) {
    if (event?.ctrlKey && this.hoveredObject) {
      // 多选，不操作
      // 将当前hover的对象根据是否在已选中列表，设置为状态
      [this.hoveredObject].forEach((obj) => {
        const index = this.selectedObjects.indexOf(obj);
        if (index >= 0) {
          obj?.selected();
          this.selectedObjects.splice(index, 1);
        } else {
          obj?.selected();
          this.selectedObjects.push(obj);
        }
      });
    } else {
      // 单选
      // 将已选中的全部恢复正常的颜色,并清空已选中列表
      this.selectedObjects.forEach((obj) => {
        obj.setNormalColor();
      });
      this.selectedObjects = [];
      // 将当前hover的对象设置为选中态
      if (this.hoveredObject) {
        this.hoveredObject.selected();
        this.selectedObjects.push(this.hoveredObject);
      }
    }
    setTimeout(() => ctx2.viewer.requestRender());
    return this.selectedObjects;
  }
  /**
   * 记录鼠标按下时的位置
   * @param e EventObject
   */
  public setPointerDownPos(e: EventObject) {
    if (e.eventName == 'pointerdown') {
      this.pointerDownPos = {
        clientPos: {
          clientX: (e.event as PointerEvent).clientX,
          clientY: (e.event as PointerEvent).clientY,
        },
        mouse: e.mouse,
      };
    } else if (e.eventName == 'pointerup') {
      this.marqueePointerUp();
    }
    return this;
  }
  public marqueePointerUp() {
    this.pointerDownPos = null;
    this.marqueeSelector?.endSelect();
    if (this.selectionBox) {
      this.deleteSelectionBox();
    }
  }
  deleteSelectionBox() {
    this.selectionBox = null;
  }
  /**
   * 框选事件
   * @param e pointerMove事件
   */
  public getSelectionBox = () => {
    if (!this.selectionBox) {
      this.selectionBox = new SelectionBox(
        this.camera,
        dimRender().dimensionGroup,
      );
    }
    return this.selectionBox;
  };

  public marqueeSelection(e: EventsRes) {
    if (!e.button.onLeft) {
      return null;
    }
    if (this.pointerDownPos == null) {
      return null;
    }
    if (
      this.pointerDownPos?.mouse.x <= e.mouse.x + 2 &&
      this.pointerDownPos?.mouse.x >= e.mouse.x - 2 &&
      this.pointerDownPos?.mouse.y <= e.mouse.y + 2 &&
      this.pointerDownPos?.mouse.y >= e.mouse.y - 2
    ) {
      return null;
    }
    const selectionBox = this.getSelectionBox();
    // 设置拾取的起止点
    const startMouse = this.pointerDownPos.mouse;
    // 存在起点
    // 设置多选框
    if (!this.marqueeSelector) {
      this.marqueeSelector = MarqueeSelector(this.pointerDownPos.clientPos);
    } else if (!this.marqueeSelector?.activing) {
      this.marqueeSelector.setStart(this.pointerDownPos.clientPos);
    }
    selectionBox.startPoint.set(
      (startMouse.x / this.container.clientWidth) * 2 - 1,
      -(startMouse.y / this.container.clientHeight) * 2 + 1,
      0.5,
    );
    const curMouse = e.mouse;
    // 设置框选框
    const curClientPos = {
      clientX: (e.event as PointerEvent).clientX,
      clientY: (e.event as PointerEvent).clientY,
    };
    this.marqueeSelector.updateSelectArea(curClientPos);
    selectionBox.endPoint.set(
      (curMouse.x / this.container.clientWidth) * 2 - 1,
      -(curMouse.y / this.container.clientHeight) * 2 + 1,
      0.5,
    );
    const selected = selectionBox.select();
    const parentUuids = [];
    this.clickNull();
    selected.forEach((item) => {
      if (isDimObject(item.parent)) {
        if (!parentUuids.includes(item.parent.uuid)) {
          parentUuids.push(item.parent.uuid);
          this.selectedObjects.push(item.parent);
        }
      }
    });
    this.selectedObjects.forEach((obj) => {
      if (isFunction(obj?.selected)) {
        obj?.selected?.();
      }
    });
  }
}
export const dimPicker = () => {
  return DimPicker.getInstance();
};

export const isDimObject = (obj: Object3D) => {
  return (
    obj instanceof DimLinear ||
    obj instanceof DimRadiusTool ||
    obj instanceof DimDiameterTool ||
    obj instanceof DimAngleTool
  );
};

export const getObjectInfo = <T>(object: Object3D): T | undefined => {
  return object?.userData as T;
};
